package com.nineclock.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.PutObjectResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.nineclock.common.constant.MessageConstant;
import com.nineclock.common.constant.NcConstant;
import com.nineclock.common.constant.SMSConstant;
import com.nineclock.common.entity.Result;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.oss.OssProperties;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.message.enums.MessageTypeEnum;
import com.nineclock.message.pojo.NcMessage;
import com.nineclock.system.dto.*;
import com.nineclock.system.mapper.*;
import com.nineclock.system.pojo.*;
import com.nineclock.system.service.SmsService;
import com.nineclock.system.service.SysCompanyService;
import com.nineclock.system.service.SysCompanyUserService;
import com.nineclock.system.utils.HxImManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Service
@Transactional
@Slf4j
public class SysCompanyServiceImpl implements SysCompanyService {

    @Autowired
    private SysCompanyMapper companyMapper;
    @Autowired
    private OSS ossClient;
    @Autowired
    private OssProperties ossProperties;
    @Autowired
    private SysCompanyUserMapper companyUserMapper;

    @Autowired
    private SmsService smsService;
    @Autowired
    private SysCompanyUserService companyUserService;
    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysCompanyUserRoleMapper companyUserRoleMapper;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private HxImManager hxImManager;

    /**
     * 根据用户ID查询企业列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<SysCompanyDTO> queryCompanyByUserId(Long userId) {

        //校验参数
        if (userId == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        /**
         * 方式一 MybatisPlus
         */
//        //1.根据用户ID查询企业ID
//        LambdaQueryWrapper<SysCompanyUser> companyUserWrapper = new LambdaQueryWrapper<>();
//        //companyUserWrapper.eq()
//        companyUserWrapper.eq(SysCompanyUser::getUserId, userId);
//        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(companyUserWrapper);
//        //判断
//        if (CollectionUtil.isEmpty(companyUserList)){
//            //没有集合没有数据
//            throw new NcException(ResponseEnum.USER_NOT_JOIN_COMPANY);
//        }
//
//        List<Long> idList = companyUserList.stream().map(sysCompanyUser -> {
//            Long companyId = sysCompanyUser.getCompanyId();
//            return companyId;
//        }).collect(Collectors.toList());
//
//        //2.根据企业ID查询企业列表
//        LambdaQueryWrapper<SysCompany> companyWrapper = new LambdaQueryWrapper<>();
//        //companyWrapper.in()
//        companyWrapper.in(SysCompany::getId, idList);
//        List<SysCompany> companyList = companyMapper.selectList(companyWrapper);

        /**
         * 方式二 子查询(MybatisPlus不能实现)
         */
        List<SysCompany> companyList = companyMapper.queryCompanyByUserId(userId);

        //组装数据返回
        return BeanHelper.copyWithCollection(companyList, SysCompanyDTO.class);
    }

    /**
     * 获取企业的详细信息
     *
     * @return
     */
    @Override
    public SysCompanyDTO queryCompany() {

        //获取当前登陆用户关联的企业ID
        Long companyId = CurrentUserHolder.get().getCompanyId();

        //根据企业ID查询企业数据信息
        SysCompany company = companyMapper.selectById(companyId);
        if (company == null) {
            throw new NcException(ResponseEnum.COMPANY_NOT_FOUND);
        }
        //组装数据返回
        return BeanHelper.copyProperties(company, SysCompanyDTO.class);
    }

    /**
     * 图片上传
     *
     * @param file
     * @return
     */
    @Override
    public String uploadFile(MultipartFile file) {

        //1.参数校验
        if (file == null) {
            throw new NcException(ResponseEnum.FILE_NOT_FOUND);
        }

        //2.校验文件类型
        String type = file.getContentType();
        //判定文件类型
        if (!NcConstant.ALLOWED_IMG_TYPES.contains(type)) {
            throw new NcException(ResponseEnum.INVALID_FILE_TYPE);
        }
        //判定图片大小是否超过项目限制
        if (file.getSize() > NcConstant.maxFileSize) {
            throw new NcException(ResponseEnum.FILE_SIZE_EXCEED_MAX_LIMIT);
        }

        //3.上传文件至阿里云OSS

        //组装文件名
        String fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")) + "-" + file.getOriginalFilename();

        try {
            //文件流上传
            PutObjectResult objectResult = ossClient.putObject(ossProperties.getBucketName(), fileName, file.getInputStream());

        } catch (IOException e) {
            e.printStackTrace();
            throw new NcException(ResponseEnum.FILE_UPLOAD_ERROR);
        }

        //4.组装URL, 并返回
        //https://nineclock374.oss-cn-beijing.aliyuncs.com/
        String imageUrl = ossProperties.getHost() + fileName;

        return imageUrl;
    }

    /**
     * 更新当前企业信息
     *
     * @param companyDTO
     */
    @Override
    public void updateCompany(SysCompanyDTO companyDTO) {
        //参数校验
        if (companyDTO == null || StrUtil.isEmpty(companyDTO.getName()) || StrUtil.isEmpty(companyDTO.getLogo())) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //组装企业信息,更新企业信息
        Long companyId = CurrentUserHolder.get().getCompanyId();

        SysCompany company = BeanHelper.copyProperties(companyDTO, SysCompany.class);
        company.setId(companyId);
        companyMapper.updateById(company);

        //更新企业 员工信息 sysCompanyUser
        //update sys_company_user set company_name = '传智教育' where company_id = 1;
        //自定义Mapper接口方法 updateCompanyUserByCompanyId
        companyUserMapper.updateCompanyUserByCompanyId(companyDTO.getName(), companyId);
    }

    /**
     * 更改企业主管理员信息
     *
     * @param managerDTO
     */
    @Override
    public void changeAdmin(SysChangeMainManagerDTO managerDTO) {
        //1. 参数校验
        if (managerDTO == null || StrUtil.isEmpty(managerDTO.getCode()) || managerDTO.getUserId() == null) {
            log.error("请求参数不合法");
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //2. 校验验证码是否正确
        //先获取当前用户的基本信息
        Long companyId = CurrentUserHolder.get().getCompanyId();
        // LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        // wrapper.eq(SysCompanyUser::getCompanyId, companyId);
        // wrapper.eq(SysCompanyUser::getId, managerDTO.getUserId());
        //直接根据ID去查询
        SysCompanyUser companyUser = companyUserMapper.selectById(managerDTO.getUserId());
        String mobile = companyUser.getMobile();

        //校验验证码
        Boolean verify = smsService.verify(mobile, "3", managerDTO.getCode());
        if (!verify) {
            throw new NcException(ResponseEnum.CODE_IMAGE_ERROR);
        }

        //3. 删除原有的企业系统管理员
        //获取原来的系统管理员
        SysCompanyUserDTO companyUserDTO = companyUserService.queryCurrentAdmin();
        //查询当前企业管理员roleId
        //组装条件
        LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysRole::getCompanyId, companyId);
        roleWrapper.eq(SysRole::getRoleName, NcConstant.ADMIN_ROLE_SYS);
        //执行查询
        SysRole sysRole = roleMapper.selectOne(roleWrapper);

        //删除原有的企业系统管理员角色与员工关系
        //组装条件
        LambdaQueryWrapper<SysCompanyUserRole> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(SysCompanyUserRole::getCompanyId, companyId);
        deleteWrapper.eq(SysCompanyUserRole::getRoleId, sysRole.getId());
        deleteWrapper.eq(SysCompanyUserRole::getCompanyUserId, companyUserDTO.getId());
        //执行删除
        companyUserRoleMapper.delete(deleteWrapper);

        //4. 新增系统管理员
        SysCompanyUserRole companyUserRole = new SysCompanyUserRole();
        companyUserRole.setCompanyId(companyId);
        companyUserRole.setRoleId(sysRole.getId());
        companyUserRole.setCompanyUserId(managerDTO.getUserId());

        companyUserRoleMapper.insert(companyUserRole);
    }

    /**
     * 根据企业的关键字, 模糊查询企业列表
     *
     * @param keyword
     * @return
     */
    @Override
    public List<SysCompanyDTO> queryByKeyword(String keyword) {
        //1. 参数校验
        if (StrUtil.isEmpty(keyword)) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //2. 组装查询条件
        LambdaQueryWrapper<SysCompany> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(SysCompany::getName, keyword);

        List<SysCompany> sysCompanies = companyMapper.selectList(wrapper);
        //3. 返回
        return BeanHelper.copyWithCollection(sysCompanies, SysCompanyDTO.class);
    }

    /**
     * 申请加入企业 --- (即时通信功能)注册用户到环信
     *
     * @param companyUserDTO
     */
    @Override
    public void applyJoinCompany(SysApplyJoinCompanyUserDTO companyUserDTO) {

        //1. 参数校验
        if (companyUserDTO == null || StrUtil.isEmpty(companyUserDTO.getUserName()) || companyUserDTO.getUserId() == null || companyUserDTO.getCompanyId() == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //2. 组装信息,插入员工表
        SysCompanyUser companyUser = new SysCompanyUser();

        companyUser.setUserName(companyUserDTO.getUserName());
        companyUser.setCompanyId(companyUserDTO.getCompanyId());
        companyUser.setCompanyName(companyUserDTO.getCompanyName());
        companyUser.setUserId(companyUserDTO.getUserId());
        companyUser.setEmail(companyUserDTO.getEmail());
        companyUser.setMobile(companyUserDTO.getMobile());
        companyUser.setRemark(companyUserDTO.getApplyReason()); //申请理由
        companyUser.setPost(companyUserDTO.getPost()); //职位
        companyUser.setImageUrl(companyUserDTO.getImageUrl()); //头像
        companyUser.setEnable((short) 0);//未审核

        companyUserMapper.insert(companyUser);

        //3. 更新用户数据
        SysUser sysUser = userMapper.selectById(companyUserDTO.getUserId());
        if (sysUser != null) {
            sysUser.setUsername(companyUserDTO.getUserName());
            sysUser.setEmail(companyUserDTO.getEmail());
            sysUser.setLastLoginCompanyId(companyUserDTO.getCompanyId()); //设置用户最后登陆的企业ID为当前加入的企业

            userMapper.updateById(sysUser);
        }

        //4. TODO 发送消息到MQ , 推送消息,通知管理员

        //获取当前的系统管理员
        SysCompanyUser admin = companyUserMapper.queryCurrentAdminByCompanyId(companyUserDTO.getCompanyId());
        //SysCompanyUserDTO admin = companyUserService.queryCurrentAdmin();
        //注册用户没有登陆过 不能从ThreadLocal中获取数据

        //组装消息
        NcMessage ncMessage = new NcMessage();
        ncMessage.setCompanyId(String.valueOf(companyUserDTO.getCompanyId()));
        ncMessage.setApplyUserId(companyUserDTO.getUserId()); //申请用户ID
        ncMessage.setApplyUsername(companyUserDTO.getUserName()); //申请用户名
        ncMessage.setApproveStatue(0);//审核状态
        ncMessage.setUseStatus(0);//未读
        ncMessage.setContent(companyUserDTO.getUserName() + " 申请加入企业,请及时审批!");

        ncMessage.setApproveUserId(admin.getUserId());//审核用户ID
        ncMessage.setApproveUsername(admin.getUserName());//审核用户名

        ncMessage.setCreateTime(new Date());
        ncMessage.setTargets(Collections.singletonList(admin.getMobile()));//推送目标 按别名推送 -> 手机号
        ncMessage.setMessageType(MessageTypeEnum.COMPANY_APPLY.getType());//消息类型

        //发送消息到MQ
        rocketMQTemplate.convertAndSend("messagePushTopic", ncMessage);
        log.info("发送消息到MQ , :" + ncMessage);

        //5. TODO 申请用户注册到环信云
        //username password  nickname(可选)
        sysUser.setUsername(sysUser.getMobile());
        sysUser.setPassword("123456");

        hxImManager.registerUser2HuanXing(sysUser);
        log.info("注册用户到环信云");

    }

    /**
     * 审批加入企业
     * @param allowedDTO
     */
    @Override
    public void allowedJoinCompany(SysAllowedJoinCompanyUserDTO allowedDTO) {

        //参数校验
        if (allowedDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //更新用户信息
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper();
        wrapper.eq(SysCompanyUser::getUserId,allowedDTO.getApplyUserId()); //申请者ID
        wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId()); //企业ID(ThreadLocal中)

        SysCompanyUser companyUser = companyUserMapper.selectOne(wrapper);
        if (companyUser != null){
            //getApproved true --> 1  false --> 0
            companyUser.setEnable(allowedDTO.getApproved() ? (short)1 : (short) 0);
            companyUserMapper.updateById(companyUser); //更新用户
        }

        //审核通过
        if (allowedDTO.getApproved()){
            //发送消息到MQ ----> 更新消息状态
            rocketMQTemplate.convertAndSend("allowedJoinCompanyTopic",allowedDTO.getNotifyMsgId());

            //推送消息给申请用户
            SysUser user = userMapper.selectById(allowedDTO.getApplyUserId());
            NcMessage message = new NcMessage();

            message.setApplyUserId(allowedDTO.getApplyUserId()); //申请用户ID
            message.setApplyUsername(user.getUsername()); //申请用户名
            message.setContent(user.getUsername() + ": 您申请加入企业已经通过审核");

            message.setApproveUserId(CurrentUserHolder.get().getId()); //审核人ID
            message.setApproveUsername(CurrentUserHolder.get().getUsername()); //审核人姓名
            message.setCreateTime(new Date());

            message.setMessageType(MessageConstant.COMPANY_APPLY_PASS); //消息类型
            message.setTargets(Collections.singletonList(user.getMobile())); //推送目标 (需要传入集合)

            log.info("发送消息到MQ" + message);
            rocketMQTemplate.convertAndSend("messagePushTopic", message);
        }

    }
}